import React, { useState, useEffect, useCallback } from 'react';
import { Layout, Button, Tooltip, Modal } from 'antd'
import { useWebWorkerFromWorker } from 'react-webworker-hook'
import { SaveOutlined, AlignLeftOutlined, RollbackOutlined, FileTextOutlined } from '@ant-design/icons'
import connect from '@/utils/easyDva'
import FileTree from '@/component/fileTree'
import XmlEditor from '@/component/xmlEditor'
import FileInput from '@/component/fileInput'
import { dirHandle2fileTree, setParentError } from '@/utils/files'
// 检测文件树进行代码校验
import lintFileTreeWorker from '@/utils/webWorker/lintFileTree.webworker'
import LearnModal from './learnModal'
import EditRuleModal from './editRuleModal'
import Store from '@/utils/store'
import MenuTool from './menuTool'
import styles from './index.less'

const { Sider, Content } = Layout

const worker4LintFileTree = new lintFileTreeWorker()

// 主页
function Home(props) {
  const { fileTree, currentTags, currentText, currentNode, isShowEditTagsModal, haveSyncText, haveSelectXml, setField } = props
  const [isShowLearnModal, showLearnModal] = useState(false)// 展示学习对话框
  const [editor, setEditor] = useState(null) // 编辑器实例
  const [lintedFileTree, startLintFileTree] = useWebWorkerFromWorker(worker4LintFileTree)

  // 初始化
  useEffect(() => {
    Store.getTagsList().then((tagsList) => {
      setField({
        tagsList
      })
      const lastTagsName = Store.getLastTagsName()
      if (lastTagsName) {
        const tagsItem = tagsList.find(l => l.name === lastTagsName)
        if (tagsItem) {
          setField({
            currentTags: tagsItem.tags || {},
            currentTagsName: tagsItem.name
          })
        } else {
          setField({
            currentTags: {},
            currentTagsName: ''
          })
        }
      }
    })
  }, [setField])

  useEffect(() => {
    if (lintedFileTree) {
      setField({
        fileTree: lintedFileTree
      })
    }
  }, [lintedFileTree, setField])

  /**
   * 编辑器文本变更
   */
  const handleChangeText = (editor, data, value) => {
    setField({
      currentText: value,
      haveSyncText: false
    })
  }

  /**
   * 切换到新文件
   */
  const switchToNewXml = async (node) => {
    const file = await node.handle.getFile()
    const text = await file.text()
    setField({
      currentNode: node,
      currentText: text,
      haveSelectXml: true
    })
  }

  /**
   * 选中XML文件节点
   * @param {节点信息} node 
   */
  const handleSelectXml = async (node) => {
    if (node === null) {
      setField({
        haveSyncText: true,
        haveSelectXml: false,
        currentNode: null,
        currentText: ''
      })
      return
    }
    if (haveSyncText) {// 当前文件文本已保存的情况
      switchToNewXml(node)
    } else {// 当前文件文本未保存的情况
      Modal.confirm({
        icon: null,
        title: '当前文件文本未保存，切换文件前请确认是否保存',
        okText: '保存修改',
        cancelText: '取消修改',
        onOk: async () => {
          await handleSaveFile()
          switchToNewXml(node)
        },
        onCancel() {
          switchToNewXml(node)
          setField({
            haveSyncText: true
          })
        }
      })
    }
  }

  /**
   * 打开文件夹
   */
  const handleOpenFolder = async (dirHandle) => {
    const fileTree = await dirHandle2fileTree(dirHandle)
    startLintFileTree({ fileTree, currentTags })
  }

  /**
   * 约束规则改变，重新检测
   */
  const handleReLint = async () => {
    startLintFileTree({ fileTree, currentTags })
    // 编辑器重新校验
    if (editor && editor.doc && editor.doc.cm) {
      editor.doc.cm.performLint()
    }
  }

  /**
   * 编辑器接收到代码校验错误
   */
  const handleReceiveError = useCallback((errors) => {
    if (currentNode && fileTree && fileTree.length !== 0) {
      currentNode.isError = errors.length > 0
      setParentError(currentNode.parent)
    }
    setField({
      fileTree: [...fileTree]
    })
  }, [currentNode, fileTree, setField])


  /**
   * 保存当前文件内容
   */
  const handleSaveFile = async () => {
    const writable = await currentNode.handle.createWritable();
    // 将文件写入流
    await writable.write(currentText);
    // 关闭文件，并写入到硬盘
    await writable.close();
    setField({
      haveSyncText: true
    })
  }

  /**
   * 格式化文本
   */
  const handleFormat = () => {
    const totalLines = editor.doc.cm.lineCount();
    editor.doc.cm.autoFormatRange({ line: 0, ch: 0 }, { line: totalLines })
  }

  /**
   * 撤回操作
   */
  const handleBack = () => {
    editor.doc.undo()
  }

  /**
   * 注释操作
   */
  const handleNote = () => {
    editor.doc.cm.toggleComment()
  }

  /**
   * 刷新树节点
   */
  const handleRefreshTree = () => {
    setField({
      fileTree: [...fileTree]
    })
  }

  /**
   * 阻止默认的浏览器右键行为
   */
  const handleContextMenu=(e)=>{
    e.stopPropagation()
    e.preventDefault()
  }

  return (
    <div className={styles.container} onContextMenu={handleContextMenu} >
      <MenuTool onAddTags={() => showLearnModal(true)} onOpenFolder={handleOpenFolder} />
      <Layout>
        <Sider width={400}>
          {
            fileTree.length === 0 ? <>
              <div className={styles.tips}>你尚未打开文件夹</div>
              <FileInput onChange={handleOpenFolder} >
                <Button type="primary" className={styles.btnOpenFolder}>打开文件夹</Button>
              </FileInput>
            </> : <FileTree dataSource={fileTree} onSelectXml={handleSelectXml} currentNode={currentNode} onRefreshTree={handleRefreshTree} />
          }
        </Sider>
        <Content>
          <div className={isShowEditTagsModal ? styles.editorAdapt : styles.editor}>
            {
              haveSelectXml ? <>
                <div className={styles.editorBar}>
                  <div className={styles.rightTips}>
                    当前编辑文件：{currentNode.title}
                  </div>
                  <div className={styles.leftBtnGroup}>
                    <Tooltip title="撤回：Ctrl+Z" overlayClassName={styles.titleClass} color="#fff" overlayInnerStyle={{ color: '#233' }}>
                      <RollbackOutlined className={styles.btnIcon} onClick={handleBack} />
                    </Tooltip>
                    <Tooltip title="注释：Ctrl+/" overlayClassName={styles.titleClass} color="#fff" overlayInnerStyle={{ color: '#233' }}>
                      <AlignLeftOutlined className={styles.btnIcon} onClick={handleNote} />
                    </Tooltip>
                    <Tooltip title="格式化：Shift+Alt+F" overlayClassName={styles.titleClass} color="#fff" overlayInnerStyle={{ color: '#233' }}>
                      <FileTextOutlined className={styles.btnIcon} onClick={handleFormat} />
                    </Tooltip>
                    <Tooltip title="保存：Ctrl+S" overlayClassName={styles.titleClass} color="#fff" overlayInnerStyle={{ color: '#233' }}>
                      <SaveOutlined className={styles.btnIcon} onClick={handleSaveFile} />
                    </Tooltip>
                    {
                      !haveSyncText && <span className={styles.danger}>文件未保存</span>
                    }
                  </div>
                </div>
                <XmlEditor tags={currentTags} value={currentText} onChange={handleChangeText} onErrors={handleReceiveError} onGetEditor={setEditor} onSave={handleSaveFile} />
              </> : <div className={styles.instructions}>
                  <h1>使用说明</h1>
                  <ul>
                    <li>新增约束规则。点击菜单栏的约束规则->新增约束规则。选择指定的包含xml文件的文件夹，开始自动学习xml文件。输入约束规则名称后，保存在浏览器本地存储中。</li>
                    <li>选择约束规则。选择约束规则后，可以手动调整约束规则。</li>
                    <li>编辑XML。通过左侧的打开文件夹，打开想要编辑的XML所在文件夹，编辑后保存即可。</li>
                  </ul>
                </div>
            }
          </div>
          {isShowEditTagsModal && <EditRuleModal onReLint={handleReLint} />}
        </Content>
      </Layout>
      {isShowLearnModal && <LearnModal onClose={() => { showLearnModal(false) }} />}
    </div>
  )
}

export default connect(Home)
